#include "handle.hpp"
#include "process_enumerator.h"

#include <Windows.h>

#include <iostream>
#include <string_view>
#include <vector>

int main()
{
    constexpr std::wstring_view interceptor_lib = L"C:\\Users\\user\\Documents\\mbi111\\build\\Release\\mbi111_interceptor.dll";
    constexpr std::size_t bytes_count = (interceptor_lib.size() + 1) * sizeof(decltype(interceptor_lib)::value_type);
    const auto load_library = reinterpret_cast<HMODULE (*)(LPCWSTR)>(::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryW"));
    std::vector<std::pair<windows::handle, PWSTR>> memories;

    windows::process_enumerator process_enumerator;
    for (auto process = process_enumerator.first(); process; process = process_enumerator.next())
    {
        std::wcout << process->name << std::endl;

        if (process->id == ::GetCurrentProcessId())
            continue;

        windows::handle handle = ::OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, process->id);
        const auto library_name = reinterpret_cast<PWSTR>(::VirtualAllocEx(handle, NULL, bytes_count, MEM_COMMIT, PAGE_READWRITE));
        if (!library_name)
            continue;

        if (!::WriteProcessMemory(handle, library_name, interceptor_lib.data(), bytes_count, NULL))
            continue;

        windows::handle thread_id = ::CreateRemoteThread(handle, NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(load_library), library_name, 0, NULL);
        if (!thread_id)
            std::cerr << "can't remote thread creating";
        else
            memories.push_back({std::move(handle), library_name});

        std::wcout << process->name << ' ' << L"success" << std::endl;
    }

    for (auto& [thread, lib_name] : memories)
    {
        ::WaitForSingleObject(thread, INFINITE);
        ::VirtualFreeEx(thread, lib_name, 0, MEM_RELEASE);
    }

    std::cout << "OK" << std::endl;
    std::cin.get();

    return 0;
}
